<script setup>
import { ref, reactive, getCurrentInstance, onMounted, h, nextTick } from "vue";
import { goRouter } from "@/utils";
import { accAdd, accSub, accMul } from '@/utils/count'

import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { DRACOLoader  } from 'three/addons/loaders/DRACOLoader'

// 用于模型边缘高亮
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
import { OutlinePass } from "three/addons/postprocessing/OutlinePass.js";
import { ShaderPass } from "three/addons/postprocessing/ShaderPass.js";
import { FXAAShader } from "three/addons/shaders/FXAAShader.js";
import { SMAAPass } from "three/addons/postprocessing/SMAAPass.js";
import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";

const instance = getCurrentInstance();
const _this = instance.appContext.config.globalProperties; //vue3获取当前this

// 组件中使用，接收传参的
// let propsData = defineProps({
  
// })
// 组件中使用，接收事件的
const emits = defineEmits(['cameraClick']);

onMounted(() => {
  init();
  loadGltf(); // 添加网络模型
  addLight(); // 添加光源
});

function refreshThree(){
  renderer.render(scene, camera); //执行渲染操作
}

const threeRef = ref(null);
let scene = null;
let camera = null;
let mesh = null;
let renderer = null;

let intersects = []; //几何体合集
let meshGroup = null;
let pointer = new THREE.Vector2(0, 0, 0);
let raycaster = new THREE.Raycaster();

function init() {
  scene = new THREE.Scene();
  scene.background = new THREE.Color('#002356');
  //创建一个长方体几何对象Geometry
  const geometry = new THREE.BoxGeometry(1, 1, 1); 
  //创建一个材质对象Material
  const material = new THREE.MeshBasicMaterial({
    color: 0xff0000,//0xff0000设置材质颜色为红色
    transparent: true,//开启透明
    opacity: 0,//设置透明度
    polygonOffset: true, 
    polygonOffsetFactor: 1, 
    polygonOffsetUnits: 1 
  }); 
  mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
  //设置网格模型在三维空间中的位置坐标，默认是坐标原点
  mesh.position.set(0, 0, 0);
  scene.add(mesh);

  let threeDom = threeRef.value;
  const width = threeDom.clientWidth; //宽度
  const height = threeDom.clientHeight; //高度

  // 实例化一个透视投影相机对象
  camera = new THREE.PerspectiveCamera(45, width / height, 1, 2000);
  camera.position.set(0, 10, 50);  
  camera.lookAt(mesh.position);//指向mesh对应的位置

  renderer = new THREE.WebGLRenderer({
    antialias: true //抗锯齿
  });
  renderer.autoClear = false; 
  renderer.shadowMap.enabled = true;  //允许在场景中使用阴影贴图
  renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
  renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
  renderer.render(scene, camera); //执行渲染操作
  threeDom.appendChild(renderer.domElement);

  // XYZ 线
  // const axesHelper = new THREE.AxesHelper(90);
  // scene.add(axesHelper);

  // 鼠标自由视角滑动
  const controls = new OrbitControls(camera, renderer.domElement);
  controls.addEventListener('change',  () => {
    renderer.render(scene, camera); //执行渲染操作
  });//监听鼠标、键盘事件

  groupCamera.name = '摄像头集合';
  group.add( groupCamera);
  threeDom.addEventListener('click', meshOnClick);
  threeDom.addEventListener('mousemove', meshOnMousemove);
};

let group = new THREE.Group();
let rotateState = 'run';    // run：正在旋转  stop：暂停  
let rotateId = 0;
// 旋转动画
function renderGroup(){
  renderer.render(scene,camera);
  group.rotateY(0.001);
  rotateId = requestAnimationFrame(renderGroup);
}
// 添加网络模型
function loadGltf() {
  const loader = new GLTFLoader()
  const dracoLoader = new DRACOLoader()
  dracoLoader.setDecoderPath('/draco/')
  dracoLoader.preload()
  loader.setDRACOLoader(dracoLoader);
  loader.load("static/glb/scene.glb", (gltf) => {
    gltf.scene.children.map(i => {
      if (i.name == "平面") {
        i.receiveShadow = true;
      }
      if (i.name == "建筑实体") {
        i.castShadow = true;
        i.material.transparent = true;
        i.material.opacity = 0.4;
        i.material.emissive = new THREE.Color('#0034e3')
      }
      if (i.name == "建筑线框") {
        i.castShadow = true;
        i.material.transparent = true;
        i.material.opacity = 0.4;
      }
      if (i.name == "底座") {
        i.receiveShadow = true;
      }
      if (i.name == "光环") {
        // i.receiveShadow = true;
        i.material.transparent = true;
        i.material.opacity = 0;
      }
      if (i.name.indexOf("柱子") > -1) {
        i.material.color = new THREE.Color('#ffffff')
        i.material.emissive = new THREE.Color('#0034e3')
      }
      if (i.name.indexOf("平面00") > -1) {
        // i.material.color = new THREE.Color('#1C2243')
        i.material.emissive = new THREE.Color('#4471e3')
      }
      return i;
    })
    gltf.scene.scale.set(3, 3, 3);
    
    group.add(gltf.scene)
    group.position.set(-16, -20, 0);
    group.name = '网络模型'

    scene.add(group)
    renderer.render(scene, camera);
    renderGroup();
  }, (xhr) => {
    // console.log((xhr.loaded / xhr.total) * 100 + '% loaded', xhr)
  }, (error) => {
    console.error(error)
  })
}
// 添加光源
function addLight(){
  const directionalLight = new THREE.DirectionalLight( 0xffffff, 6 );
  directionalLight.position.set(6, 5, 1);//点光源放在x轴上
  directionalLight.castShadow = true; // default false
  scene.add(directionalLight ); //点光源添加到场景中        // default
}
// 停止旋转
function stopClick(){
  if (rotateState === 'run') {
    rotateState = 'stop';
    if (rotateId) {
      window.cancelAnimationFrame(rotateId);
    }
  }else{
    rotateState = 'run';
    renderGroup();
  }
}
let colorObj = [
  {alarmState: 0, color: '#ABAEB1'},
  {alarmState: 1, color: '#FB393C'},
  {state: 2, color: '#384CFF'},
]
let groupCamera = new THREE.Group();    // 摄像头集合
let multiple = 1.7;   // 点击摄像头放大的倍数
// 添加摄像头
function addCamera(arr = [], cameraId = null){
  if (groupCamera.children.length) {
    groupCamera.children = [];
  }
  //创建一个长方体几何对象Geometry
  let origin = {x: -1.57, y: 5.38, z: -1.67};   // 重定义原点坐标
  let _unitX = 0.1465;   // X 的单位
  let _unitY = 0.15;   // Y 的单位
  let _unitZ = 0.1468;   // X 的单位
  arr.forEach(i => {
    let position = i.coordinate.split(',');
    const geometry = new THREE.SphereGeometry( 0.3, 64, 32 );
    let color = '';
    if (i.alarmState == 1) {
      color = '#FB393C';  // 有告警，紅色
    }else{
      if (i.state == 1) {
        color = '#384CFF';  // 在线，蓝色
      }else{
        color = '#ABAEB1';  // 不在线，灰色
      }
    }
    // colorObj.find(j => j.alarmState == i.alarmState)?.color;
    const material = new THREE.MeshBasicMaterial({ color: color || "#ABAEB1" });
    const sphere = new THREE.Mesh( geometry, material );
    let yX = position[0] || 0;
    let yY = position[1] || 0;
    let yZ = position[2] || 0;
    let X = accAdd(origin.x, accMul(_unitX, yX));
    let Y = accAdd(origin.y, accMul(_unitY, yY));
    let Z = accAdd(origin.z, accMul(_unitZ, yZ));
    sphere.position.set(X, Y, Z);
    sphere['cameraData'] = i;
    sphere.name = '摄像头_' + i.id;
    if (i.id == cameraId) {
      sphere.scale.set(multiple, multiple, multiple);
    }
    groupCamera.add( sphere );
  })
  renderer.render(scene, camera);
}
// 摄像头点击事件
function meshOnClick(event) {
  pointer.x = ( event.clientX / window.innerWidth ) * 2 - 1;
  pointer.y = -( event.clientY / window.innerHeight ) * 2 + 1;
  raycaster.setFromCamera( pointer, camera );
  //geometrys为需要监听的Mesh合集，可以通过这个集合来过滤掉不需要监听的元素例如地面天空
  //true为不拾取子对象
  intersects = raycaster.intersectObjects( groupCamera.children, true );
  //被射线穿过的几何体为一个集合，越排在前面说明其位置离端点越近，所以直接取[0]
  if ( intersects.length > 0 ) {
    meshGroup = intersects[0].object;
    emits('cameraClick', true, meshGroup);
    meshGroup?.scale.set(multiple, multiple, multiple);
  } else {
    emits('cameraClick', false)
    meshGroup?.scale.set(1, 1, 1);
  }
}
// 摄像头 hover事件
function meshOnMousemove(event) {
  pointer.x = ( event.clientX / window.innerWidth ) * 2 - 1;
  pointer.y = -( event.clientY / window.innerHeight ) * 2 + 1;
  raycaster.setFromCamera( pointer, camera );
  //geometrys为需要监听的Mesh合集，可以通过这个集合来过滤掉不需要监听的元素例如地面天空
  //true为不拾取子对象
  intersects = raycaster.intersectObjects( groupCamera.children, true );
  //被射线穿过的几何体为一个集合，越排在前面说明其位置离端点越近，所以直接取[0]
  if ( intersects.length > 0 ) {
    document.body.style.cursor = "pointer";
  } else {
    document.body.style.cursor = "default";
  }
}
// cameraId：要active的摄像头ID  cameraIdOld：要清除active的摄像ID
function changeCamera(cameraId = '暂无', cameraIdOld = '暂无'){
  groupCamera.children.forEach(i => {
    if (i.name.indexOf(cameraIdOld) > -1) {
      i?.scale.set(1, 1, 1);
    }
    if (i.name.indexOf(cameraId) > -1) {
      i?.scale.set(multiple, multiple, multiple);
    }
  })
  renderer.render(scene, camera);
}

function calibration() {
  const width = threeRef.value.clientWidth; //宽度
  const height = threeRef.value.clientHeight; //高度
  renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
  renderer.render(scene, camera);
}

defineExpose({addCamera, changeCamera, refreshThree, calibration})
</script>
<template>
  <div class="demo" ref="threeRef">
    <el-button type="primary" class="stop" @click="stopClick">演示暂停</el-button>
  </div>
</template>
<style scoped lang="less">
.demo{
  width: 100vw;
  height: 100vh;
  position: absolute;
  left: 0;
  top: -80px;
  .stop{
    position: absolute;
    left: 60px;
    bottom: 60px;
    color: #ffffff;
    z-index: 500;
  }
}
</style>